home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / Samples / SprocketExamples / GlyphaIV / GlyphaIV Sources / G4Utilities.c < prev    next >
Encoding:
Text File  |  1998-07-14  |  18.0 KB  |  549 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        G4Utilities.c
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                xxx put dri here xxx
  13.  
  14.         Other Contact:        xxx put other contact here xxx
  15.  
  16.         Technology:            xxx put technology here xxx
  17.  
  18.     Writers:
  19.  
  20.         (sjb)    Steve Bollinger
  21.  
  22.     Change History (most recent first):
  23.  
  24.          <2>      7/1/98    sjb        Update to CWPro 2
  25. */
  26.  
  27.  
  28. //============================================================================
  29. //----------------------------------------------------------------------------
  30. //                                    Utilities.c
  31. //----------------------------------------------------------------------------
  32. //============================================================================
  33.  
  34. // These functions are sort of universal utility functions.  They aren't specific…
  35. // to Glypha per se.  I use these (and others) in many, many games.  Many of them…
  36. // as well are useful for any app you might write for the Mac.
  37.  
  38. #include "G4Externs.h"
  39. #include <Processes.h>
  40. #include <SegLoad.h>
  41. #include <Traps.h>
  42. #include <Resources.h>
  43. #include <TextUtils.h>
  44. #include <LowMem.h>
  45.  
  46. #define kActive                        0
  47. #define kInactive                    255
  48.  
  49.  
  50. GDHandle    thisGDevice;
  51. long        tickNext;
  52.  
  53.  
  54. //==============================================================  Functions
  55. //--------------------------------------------------------------  RandomInt
  56.  
  57. // Takes a short (range) and returns a random number from zero to range - 1.
  58.  
  59. short RandomInt (short range)
  60. {
  61.     register long    rawResult;
  62.     
  63.     rawResult = Random();
  64.     if (rawResult < 0L)
  65.         rawResult *= -1L;
  66.     rawResult = (rawResult * (long)range) / 32768L;
  67.     
  68.     return ((short)rawResult);
  69. }
  70.  
  71. //--------------------------------------------------------------  RedAlert
  72.  
  73. // Generic error function.  This is called when there is no hope of recovering
  74. // from the error.  A simple alert is brought up and the text passed in (theStr)
  75. // is displayed.  When the user clicks the Okay button, we quit to the Finder.
  76.  
  77. void RedAlert (StringPtr theStr)
  78. {
  79.     #define        kRedAlertID        128
  80.     short        whoCares;
  81.  
  82. #if GENERATINGPOWERPC
  83.     // make sure we are at full color
  84.     DSpContext_FadeGammaIn( NULL, NULL );
  85.     if( gTheContext )
  86.     {
  87.         DSpContext_SetState( gTheContext, kDSpContextState_Inactive );
  88.         DSpContext_Release( gTheContext );
  89.         DSpShutdown();
  90.     }
  91.     
  92. #endif    
  93.  
  94.     ParamText(theStr, "\p", "\p", "\p");        // Replace ^0 in alert with error mssg.
  95.     whoCares = Alert(kRedAlertID, 0L);            // Bring up alert.
  96.     ExitToShell();                                // Quit to Finder.
  97. }
  98.  
  99. //--------------------------------------------------------------  FindOurDevice
  100.  
  101. // Get a handle to the MainDevice (monitor with the Menubar).
  102.  
  103. void FindOurDevice (void)
  104. {
  105.     thisGDevice = GetMainDevice();
  106.     if (thisGDevice == 0L)                        // If a nil handle is returned...
  107.         RedAlert("\pCouldn't Find Our Device");    // call our universal error alert.
  108. }
  109.  
  110. //--------------------------------------------------------------  LoadGraphic
  111.  
  112. // Handy function that loads a PICT graphic, get's its bounds and draws it.
  113. // The port drawn to is assumed the current port.  No scaling is done.
  114.  
  115. void LoadGraphic (short resID)
  116. {
  117.     Rect        bounds;
  118.     PicHandle    thePicture;
  119.     
  120.     thePicture = GetPicture(resID);                // Load graphic from resource fork.
  121.     if (thePicture == 0L)                        // Check to see if nil (did it load?)
  122.         RedAlert("\pA Graphic Couldn't Be Loaded");
  123.     
  124.     HLock((Handle)thePicture);                    // If we made it this far, lock handle.
  125.     bounds = (*thePicture)->picFrame;            // Get a copy of the picture's bounds.
  126.     HUnlock((Handle)thePicture);                // We can unlock the picture now.
  127.     OffsetRect(&bounds, -bounds.left, -bounds.top);    // Offset bounds rect to (0, 0).
  128.     DrawPicture(thePicture, &bounds);            // Draw picture to current port.
  129.     
  130.     ReleaseResource((Handle)thePicture);        // Dispose of picture from heap.
  131. }
  132.  
  133. //--------------------------------------------------------------  CreateOffScreenPixMap
  134.  
  135. // Handles the creation of an offscreen pixmap.  Depth is assumed to be that of the…
  136. // current gDevice.  If the allocation fails (low memory, etc.) we quit to Finder.
  137.  
  138. void CreateOffScreenPixMap (Rect *theRect, CGrafPtr *offScreen)
  139. {
  140.     CTabHandle    thisColorTable;
  141.     GDHandle    oldDevice;
  142.     CGrafPtr    newCGrafPtr;
  143.     Ptr            theseBits;
  144.     long        sizeOfOff, offRowBytes;
  145.     OSErr        theErr;
  146.     short        thisDepth;
  147.     
  148.     oldDevice = GetGDevice();
  149.     SetGDevice(thisGDevice);
  150.     newCGrafPtr = 0L;
  151.     newCGrafPtr = (CGrafPtr)NewPtrClear(sizeof(CGrafPort));
  152.     if (newCGrafPtr != 0L)
  153.     {
  154.         OpenCPort(newCGrafPtr);
  155.         thisDepth = (**(*newCGrafPtr).portPixMap).pixelSize;
  156.         offRowBytes = ((((long)thisDepth * 
  157.                 (long)(theRect->right - theRect->left)) + 15L) >> 4L) << 1L;
  158.         sizeOfOff = (long)(theRect->bottom - theRect->top) * offRowBytes;
  159.         OffsetRect(theRect, -theRect->left, -theRect->top);
  160.         theseBits = NewPtr(sizeOfOff);
  161.         if (theseBits != 0L)
  162.         {
  163.             (**(*newCGrafPtr).portPixMap).baseAddr = theseBits;
  164.             (**(*newCGrafPtr).portPixMap).rowBytes = (short)offRowBytes + 0x8000;
  165.             (**(*newCGrafPtr).portPixMap).bounds = *theRect;
  166.             thisColorTable = (**(**thisGDevice).gdPMap).pmTable;
  167.             theErr = HandToHand((Handle *)&thisColorTable);
  168.             (**(*newCGrafPtr).portPixMap).pmTable = thisColorTable;
  169.             ClipRect(theRect);
  170.             RectRgn(newCGrafPtr->visRgn, theRect);
  171.             ForeColor(blackColor);
  172.             BackColor(whiteColor);
  173.             EraseRect(theRect);
  174.         }
  175.         else
  176.         {
  177.             CloseCPort(newCGrafPtr);        
  178.             DisposePtr((Ptr)newCGrafPtr);
  179.             newCGrafPtr = 0L;
  180.             RedAlert("\pCouldn't Allocate Enough Memory");
  181.         }
  182.     }
  183.     else
  184.         RedAlert("\pCouldn't Allocate Enough Memory");
  185.     
  186.     *offScreen = newCGrafPtr;
  187.     SetGDevice(oldDevice);
  188. }
  189.  
  190. //--------------------------------------------------------------  CreateOffScreenBitMap
  191.  
  192. // Creates an offscreen bitmap.  Depth is of course 1 (b & w).  If this function…
  193. // fails to create the bitmap, we post an alert and quit to the Finder.
  194.  
  195. void CreateOffScreenBitMap (Rect *theRect, GrafPtr *offScreen)
  196. {
  197.     GrafPtr        theBWPort;
  198.     BitMap        theBitMap;    
  199.     long        theRowBytes;
  200.     
  201.     theBWPort = (GrafPtr)(NewPtr(sizeof(GrafPort)));
  202.     OpenPort(theBWPort);
  203.     theRowBytes = (long)((theRect->right - theRect->left + 15L) / 16L) * 2L;
  204.     theBitMap.rowBytes = (short)theRowBytes;
  205.     theBitMap.baseAddr = NewPtr((long)theBitMap.rowBytes * 
  206.         (theRect->bottom - theRect->top));
  207.     if (theBitMap.baseAddr == 0L)
  208.         RedAlert("\pCouldn't Create Bitmaps");
  209.     theBitMap.bounds = *theRect;
  210.     if (MemError() != noErr)
  211.         RedAlert("\pCouldn't Create Bitmaps");
  212.     SetPortBits(&theBitMap);
  213.     ClipRect(theRect);
  214.     RectRgn(theBWPort->visRgn, theRect);
  215.     EraseRect(theRect);
  216.     *offScreen = theBWPort;
  217. }
  218.  
  219. //--------------------------------------------------------------  ZeroRectCorner
  220.  
  221. // Offset rect to (0, 0).  This means the upper left corner of the rect is 
  222. // moved to the origin - to (0, 0) - to the upperleft corner of the port.
  223.  
  224. void ZeroRectCorner (Rect *theRect)
  225. {
  226.     theRect->right -= theRect->left;    // Move right edge by amount of left.
  227.     theRect->bottom -= theRect->top;    // Move bottom edge by amount of top.
  228.     theRect->left = 0;                    // Can now set left to zero.
  229.     theRect->top = 0;                    // Can set top edge to zero as well.
  230. }
  231.  
  232. //--------------------------------------------------------------  FlashShort
  233.  
  234. // This is a simple debugging function that will display the short passed to it…
  235. // in the upper left corner of the screen.  It's a handy way to watch the value…
  236. // of a variable while the program is running.
  237.  
  238. void FlashShort (short theValue)
  239. {
  240.     GrafPtr            wasPort, tempPort;
  241.     Str255            tempStr;
  242.     Rect            tempRect;
  243.     
  244.     GetPort(&wasPort);                        // Remember old grafPort.
  245.     
  246.     tempPort = (GrafPtr)NewPtrClear(sizeof(GrafPort));
  247.     OpenPort(tempPort);                        // Create a new empty port.
  248.     
  249.     NumToString((long)theValue, tempStr);    // Convert value passed in to a string.
  250.     MoveTo(20, 40);                            // Move the pen to the upperleft corner.
  251.     SetRect(&tempRect, 18, 20, 122, 42);    // Create a rect up there as well.
  252.     EraseRect(&tempRect);                    // Erase the rect (to make a white hole).
  253.     DrawString(tempStr);                    // And draw our text into that hole.
  254.     
  255.     ClosePort(tempPort);                    // Get rid of out temp port.
  256.     SetPort((GrafPtr)wasPort);                // And set port back to the old one.
  257. }
  258.  
  259. //--------------------------------------------------------------  LogNextTick
  260.  
  261. // Simple function to set a global (tickNext) to the current TickCount() plus…
  262. // some offset.  We'll then wait for TickCount() to exceed that global.  We use…
  263. // this function and the function below to regulate animation speeds (remember…
  264. // your game may be run on a slow Mac or a fast one - we need a way to keep the…
  265. // motion consistent.  I love when the comments are longer than the function.
  266. // (Not really.)
  267.  
  268. void LogNextTick (long howMany)
  269. {
  270.     tickNext = TickCount() + howMany;        // Get machine's TickCount() and add to it.
  271. }
  272.  
  273. //--------------------------------------------------------------  WaitForNextTick
  274.  
  275. // This is the companion function to the above function (LogNextTick()).
  276. // We do nothing but loop until TickCount() catches up with (or passes) our…
  277. // global variable tickNext.
  278.  
  279. void WaitForNextTick (void)
  280. {
  281.     do
  282.     {
  283.     }
  284.     while (TickCount() < tickNext);            // Loop until TickCount() catches up.
  285. }
  286.  
  287. //--------------------------------------------------------------  TrapExists  
  288.  
  289. // A nice "test function" that test for the existence of some ToolBox trap.
  290. // Returns TRUE if the function exists, FALSE if it doesn't.
  291.  
  292. Boolean TrapExists (short trapNumber)
  293. {
  294.     #define        kUnimpTrap        0x9F
  295.     
  296.                 // Test trap number against unimplemented trap number.
  297.     return ((NGetTrapAddress(trapNumber, ToolTrap) !=
  298.             NGetTrapAddress(kUnimpTrap, ToolTrap)));
  299. }
  300.  
  301. //--------------------------------------------------------------  DoWeHaveGestalt  
  302.  
  303. // This function specifically tests for the availablity of the Gestalt() function.
  304. // It returns TRUE if Gestalt() exists, FALSE if it doesn't.
  305.  
  306. Boolean DoWeHaveGestalt (void)
  307. {
  308.     #define        kGestaltTrap    0xAD
  309.     
  310.                 // Call above function (TrapExists()) with the Gestalt() trap number.
  311.     return (TrapExists(kGestaltTrap));
  312. }
  313.  
  314. //--------------------------------------------------------------  CenterAlert
  315.  
  316. // Handy function to center any alert within the main monitor.
  317.  
  318. void CenterAlert (short alertID)
  319. {
  320.     AlertTHndl    alertHandle;
  321.     Rect        theScreen, alertRect;
  322.     short        horiOff, vertOff;
  323.     Byte        wasState;
  324.     
  325.     theScreen = qd.screenBits.bounds;        // Get main monitor's bounds.
  326.     theScreen.top += LMGetMBarHeight();        // Account for menubar height.
  327.                                             // Get handle to alert resource.
  328.     alertHandle = (AlertTHndl)GetResource('ALRT', alertID);
  329.     if (alertHandle != 0L)                    // Make sure we got it!
  330.     {                                        // Remember its "state" (locked, etc.)
  331.         wasState = HGetState((Handle)alertHandle);
  332.         HLock((Handle)alertHandle);            // We'll lock it.
  333.                                             // Get a copy of it's bounds and zero.
  334.         alertRect = (**alertHandle).boundsRect;
  335.         OffsetRect(&alertRect, -alertRect.left, -alertRect.top);
  336.                                             // Calculate offsets for centering bounds.
  337.         horiOff = ((theScreen.right - theScreen.left) - alertRect.right) / 2;    
  338.         vertOff = ((theScreen.bottom - theScreen.top) - alertRect.bottom) / 3;
  339.                                             // And offset the bounds copy.
  340.         OffsetRect(&alertRect, horiOff, vertOff + LMGetMBarHeight());
  341.                                             // Set alerts bounds to our centered rect.
  342.         (**alertHandle).boundsRect = alertRect;
  343.         HSetState((Handle)alertHandle, wasState);
  344.     }
  345. }
  346.  
  347. //--------------------------------------------------------------  RectWide
  348.  
  349. // Handy function for returning the absolute width of a rectangle.
  350.  
  351. short RectWide (Rect *theRect)
  352. {
  353.     return (theRect->right - theRect->left);
  354. }
  355.  
  356. //--------------------------------------------------------------  RectTall
  357.  
  358. // Handy function for returning the absolute height of a rectangle.
  359.  
  360. short RectTall (Rect *theRect)
  361. {
  362.     return (theRect->bottom - theRect->top);
  363. }
  364.  
  365. //--------------------------------------------------------------  CenterRectInRect
  366.  
  367. // Nice utility function that takes two rectangles and centers the first…
  368. // rectangle within the second.
  369.  
  370. void CenterRectInRect (Rect *rectA, Rect *rectB)
  371. {
  372.     short    widthA, tallA;
  373.     
  374.     widthA = RectWide(rectA);                // Get width of 1st rect.
  375.     tallA = RectTall(rectA);                // Get height of 1st rect.
  376.                                             // Do the math (center horizontally).
  377.     rectA->left = rectB->left + (RectWide(rectB) - widthA) / 2;
  378.     rectA->right = rectA->left + widthA;
  379.                                             // Do the math (center vertically).
  380.     rectA->top = rectB->top + (RectTall(rectB) - tallA) / 2;
  381.     rectA->bottom = rectA->top + tallA;
  382. }
  383.  
  384. //--------------------------------------------------------------  PasStringCopy
  385.  
  386. // This is a nice function that helps to free you from dealing with C strings.
  387. // It takes one Pascal-style string and copies it to a second.
  388.  
  389. void PasStringCopy (StringPtr p1, StringPtr p2)
  390. {
  391.     register short        stringLength;
  392.     
  393.     stringLength = *p2++ = *p1++;    // Get 1st string's length.
  394.     while (--stringLength >= 0)        // Loop through each character in 1st string.
  395.         *p2++ = *p1++;                // And copy to 2nd string.
  396. }
  397.  
  398. //--------------------------------------------------------------  CenterDialog
  399.  
  400. // Like CenterAlert(), this function centers a Dialog on the main monitor.
  401.  
  402. void CenterDialog (short dialogID)
  403. {
  404.     DialogTHndl    dlogHandle;
  405.     Rect        theScreen, dlogBounds;
  406.     short        hPos, vPos;
  407.     Byte        wasState;
  408.     
  409.     theScreen = qd.screenBits.bounds;            // Get main monitor's bounds.
  410.     theScreen.top += LMGetMBarHeight();            // Add menuBar's height.
  411.                                                 // Load up dialog from resource.
  412.     dlogHandle = (DialogTHndl)GetResource('DLOG', dialogID);
  413.     if (dlogHandle != 0L)                        // If it loaded....!
  414.     {                                            // Remember handle state.
  415.         wasState = HGetState((Handle)dlogHandle);
  416.         HLock((Handle)dlogHandle);                // We're going to lock it.
  417.                                                 // Get a copy of the dialog's bounds.
  418.         dlogBounds = (**dlogHandle).boundsRect;
  419.         OffsetRect(&dlogBounds, -dlogBounds.left, -dlogBounds.top);
  420.                                                 // Calculate how much to offset.
  421.         hPos = ((theScreen.right - theScreen.left) - dlogBounds.right) / 2;
  422.         vPos = ((theScreen.bottom - theScreen.top) - dlogBounds.bottom) / 3;
  423.                                                 // Offset ourt copy of the bounds.
  424.         OffsetRect(&dlogBounds, hPos, vPos + LMGetMBarHeight());
  425.                                                 // Set dlg's bounds to centered rect.
  426.         (**dlogHandle).boundsRect = dlogBounds;
  427.         HSetState((Handle)dlogHandle, wasState);// Restore handle's state.
  428.     }
  429. }
  430.  
  431. //--------------------------------------------------------------  DrawDefaultButton
  432.  
  433. // A nice dialog function.  This draws the bold default outline around…
  434. // item #1 in the dialog passed in.
  435.  
  436. void DrawDefaultButton (DialogPtr theDialog)
  437. {
  438.     Rect        itemRect;
  439.     Handle        itemHandle;
  440.     short        itemType;
  441.                                         // Get at the item's bounds.
  442.     GetDialogItem(theDialog, 1, &itemType, &itemHandle, &itemRect);
  443.     InsetRect(&itemRect, -4, -4);        // Inset (outset?) bounds by -4 pixels.
  444.     PenSize(3, 3);                        // Set the pen 3 pixels thick.
  445.     FrameRoundRect(&itemRect, 16, 16);    // Draw the button outline.
  446.     PenNormal();                        // And restore pen to 1 pixel thick.
  447. }
  448.  
  449. //--------------------------------------------------------------  PasStringCopyNum
  450.  
  451. // Another function to keep you from using C strings.  This one copies only a…
  452. // certain number of characters from one Pascal-style string to a second.
  453.  
  454. void PasStringCopyNum (StringPtr p1, StringPtr p2, short charsToCopy)
  455. {
  456.     short        i;
  457.     
  458.     if (charsToCopy > *p1)        // If trying to copy more chars than there are…
  459.         charsToCopy = *p1;        // Reduce the number of chars to copy to this size
  460.     
  461.     *p2 = charsToCopy;            // Set 2nd string's length to charsToCopy.
  462.     
  463.     *p2++;                        // Point to first character in 2nd string.
  464.     *p1++;                        // Point to first character in 1st string.
  465.     
  466.     for (i = 0; i < charsToCopy; i++)
  467.         *p2++ = *p1++;            // Copy the specified number of chars over.
  468. }
  469.  
  470. //--------------------------------------------------------------  GetDialogString
  471.  
  472. // Handy dialog function that returns a dialog item string.  This will be…
  473. // especially handy for getting the high score name the player enters.
  474.  
  475. void GetDialogString (DialogPtr theDialog, short item, StringPtr theString)
  476. {
  477.     Rect        itemRect;
  478.     Handle        itemHandle;
  479.     short        itemType;
  480.                                         // Get handle to dialog item.
  481.     GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
  482.     GetDialogItemText(itemHandle, theString);    // Extract text from item handle.
  483. }
  484.  
  485. //--------------------------------------------------------------  SetDialogString
  486.  
  487. // Like the above function, but this one sets a dialog items string to whatever…
  488. // you pass in.  We'll use this to set a default high score name.
  489.  
  490. void SetDialogString (DialogPtr theDialog, short item, StringPtr theString)
  491. {
  492.     Rect        itemRect;
  493.     Handle        itemHandle;
  494.     short        itemType;
  495.                                         // Get handle to dialog item.
  496.     GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
  497.     SetDialogItemText(itemHandle, theString);    // Set the items text to theString.
  498. }
  499.  
  500. //--------------------------------------------------------------  SetDialogNumToStr
  501.  
  502. // This one is like SetDialogString() above, but it takes a number (long)…
  503. // instead of a string (the function will convert the long to a string for us).
  504.  
  505. void SetDialogNumToStr (DialogPtr theDialog, short item, long theNumber)
  506. {
  507.     Str255        theString;
  508.     Rect        itemRect;
  509.     Handle        itemHandle;
  510.     short        itemType;
  511.     
  512.     NumToString(theNumber, theString);    // Convert long to a string.
  513.     GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
  514.     SetDialogItemText(itemHandle, theString);    // Set the item's text to this number/string.
  515. }
  516.  
  517. //--------------------------------------------------------------  GetDialogNumFromStr
  518.  
  519. // This one is like GetDialogString() above, but returns a long (number)…
  520. // instead of a string (it does this by converting the string to a long).
  521.  
  522. void GetDialogNumFromStr (DialogPtr theDialog, short item, long *theNumber)
  523. {
  524.     Str255        theString;
  525.     Rect        itemRect;
  526.     Handle        itemHandle;
  527.     short        itemType;
  528.                                         // Get a handle to the dialog item.
  529.     GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
  530.     GetDialogItemText(itemHandle, theString);    // Get the item's text.
  531.     StringToNum(theString, theNumber);    // Convert the text to a long.
  532. }
  533.  
  534. //--------------------------------------------------------------  DisableControl
  535.  
  536. // Another dialog utility for "graying out" buttons or other controls in a dialog.
  537.  
  538. void DisableControl (DialogPtr theDialog, short whichItem)
  539. {
  540.     Rect        iRect;
  541.     Handle        iHandle;
  542.     short        iType;
  543.                                         // Get a handle to the dialog item.
  544.     GetDialogItem(theDialog, whichItem, &iType, &iHandle, &iRect);
  545.                                         // Set it's "hilite state" to "grayed out".
  546.     HiliteControl((ControlHandle)iHandle, kInactive);
  547. }
  548.  
  549.